﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Tilver.Common;
using System.Reflection;
using System.Data;

namespace Tilver.Data
{
    /// <summary>
    /// 用Emit方式实现ORM关系映射
    /// </summary>
    internal class RowMapper
    {
        private static readonly Dictionary<Type, RowMapping> _mapCache = new Dictionary<Type, RowMapping>();
        private static object _syncLock = new object();
        public static Func<IDataReader, T> GetRowMapper<T>()
        {
            Func<IDataReader, T> ret = null;
            Type type = typeof(T);
            if (!_mapCache.ContainsKey(type))
            {
                lock (_syncLock)
                {
                    if (!_mapCache.ContainsKey(type))
                    {
                        RowMapping mapper = new RowMapping(type);
                        _mapCache.Add(type, mapper);
                        ret = new Func<IDataReader, T>(mapper.Build<T>);
                    }
                }
            }
            else
            {
                ret = new Func<IDataReader, T>(_mapCache[type].Build<T>);
            }
            return ret;
        }
        /// <summary>
        /// 获取唯一的IDataReader对象映射的实体对象(T)
        /// （IDataReader对象中只包含一条记录）
        /// </summary>
        /// <typeparam name="T">IDataReader对象映射的实体对象类型</typeparam>
        /// <param name="reader">IDataReader对象</param>
        /// <param name="rowMapper">IDataReader对象到实体对象的映射方法，如果为null，则默认要求实体对象(T)使用DataColumnAttribute定义元数据，以便反射获取实体对象</param>
        /// <returns></returns>
        public static T MapToSingle<T>(IDataReader reader, Func<IDataReader, T> rowMapper = null)
        {
            if (rowMapper == null) rowMapper = RowMapper.GetRowMapper<T>();
            T ret = default(T);
            try
            {
                if (reader.Read())
                {
                    ret = rowMapper(reader);
                }
                if (reader.Read()) throw new ArgumentException("IDataReader记录不唯一。", "reader");
            }
            finally
            {
                reader.Close();
            }
            return ret;
        }

        /// <summary>
        /// 获取IDataReader对象映射的实体对象(T)集合
        /// </summary>
        /// <typeparam name="T">IDataReader对象映射的实体对象类型</typeparam>
        /// <param name="reader">IDataReader对象</param>
        /// <param name="rowMapper">IDataReader对象到实体对象的映射方法，如果为null，则默认要求实体对象(T)使用DataColumnAttribute定义元数据，以便反射获取实体对象</param>
        /// <returns></returns>
        public static IEnumerable<T> MapToList<T>(IDataReader reader, Func<IDataReader, T> rowMapper = null)
        {
            if (rowMapper == null) rowMapper = RowMapper.GetRowMapper<T>();
            try
            {
                while (reader.Read())
                {
                    yield return rowMapper(reader);
                }
            }
            finally
            {
                reader.Close();
            }
        }
    }
    /// <summary>
    /// 实现IDataReader与实体类ORM映射
    /// </summary>
    internal class RowMapping
    {
        private object _map;

        public RowMapping(Type type)
        {
            Func<object> func = DynamicCompiler.CreateBuilder(type, true);
            this._map = func();
        }

        public T Build<T>(IDataReader dr)
        {
            IRowMapper<T> mapper = (IRowMapper<T>)this._map;
            return mapper.MapRow(dr);
        }
        /*
        private Type _type;
        private BuildHandler _buildHandler;
        private readonly Dictionary<string, SetHandler> _columnMapper = new Dictionary<string, SetHandler>();
        public RowMapping(Type t)
        {
            _type = t;
            _buildHandler = DynamicCompiler.CreateBuildHandler(t);
            PropertyInfo[] properties = (from p in _type.GetProperties()
                                         where p.IsDefined(typeof(DataColumnAttribute), true)
                                         select p).ToArray<PropertyInfo>();

            foreach (PropertyInfo property in properties)
            {
                DataColumnAttribute attr = (DataColumnAttribute)Attribute.GetCustomAttribute(property, typeof(DataColumnAttribute));
                string key = attr.ColumnName;
                SetHandler handler = DynamicCompiler.CreateSetHandler(_type, property);
                _columnMapper.Add(key, handler);
            }
        }
        private List<Action<object, SetHandler>> _propertyMapper = new List<Action<object, SetHandler>>();
        public T Build<T>(IDataReader reader)
        {
            object ret = _buildHandler();
            foreach (KeyValuePair<string, SetHandler> item in _columnMapper)
            {
                item.Value.Invoke(ret, reader[item.Key]);
            }
            return (T)ret;
        }
         * */
    }
}
